package com.tencent.wxcloudrun.service.business;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tencent.wxcloudrun.pojo.bo.ContractGenerateTask;
import com.tencent.wxcloudrun.pojo.bo.RentalContract01;
import com.tencent.wxcloudrun.pojo.po.*;
import com.tencent.wxcloudrun.service.*;
import com.tencent.wxcloudrun.util.IdUtil;
import com.tencent.wxcloudrun.util.PdfUtil;
import com.tencent.wxcloudrun.util.WinXinUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 异步合同生成服务
 */
@Service
@Slf4j
public class ContractAsyncService {
    @Resource
    private XApplyMiddleService xApplyMiddleService;
    @Resource
    private XPersonInfoService xPersonInfoService;
    @Resource
    private XHouseInfoService xHouseInfoService;
    @Resource
    private XContractTemplateService xContractTemplateService;
    @Resource
    private XFeeManageMasterService xFeeManageMasterService;
    @Resource
    private XFeeManageSonService xFeeManageSonService;
    @Resource
    private XContractManageService xContractManageService;
    @Resource
    private WinXinUtils winXinUtils;
    // 线程池
    private ExecutorService executorService;

    @PostConstruct
    public void init() {
        // 创建固定大小的线程池
        executorService = Executors.newFixedThreadPool(5);
        log.info("ContractAsyncService initialized with thread pool size: 5");
    }

    /**
     * 提交异步合同生成任务（正式签约使用）
     * 与临时合同的区别：使用实际签约时间，用于节点四的正式签约
     */
    public void submitContractGenerateTaskForFormalSign(String applyId) {
        Date date = new Date();
        try {
            // 获取申请信息
            LambdaQueryWrapper<XApplyMiddle> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(XApplyMiddle::getSonThreeId, applyId);
            XApplyMiddle applyMiddle = xApplyMiddleService.getOne(wrapper);

            if (applyMiddle == null) {
                throw new RuntimeException("申请信息不存在");
            }

            // 创建任务，标记为正式签约
            ContractGenerateTask task = new ContractGenerateTask(
                    applyId,
                    applyMiddle.getHouseId(),
                    applyMiddle.getLandId(),
                    applyMiddle.getTenantId()
            );
            task.setFormalSign(true); // 标记为正式签约

            // 异步执行合同生成
            CompletableFuture.runAsync(() -> {
                try {
                    // 获取相关信息
                    ContractData contractData = getContractData(task);
                    // 使用新的合同模板生成PDF
                    generateContractPdf(contractData, task);

                    XFeeManageMaster xFeeManageMaster = new XFeeManageMaster();
                    String busId = cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr();
                    xFeeManageMaster.setBusinessId(busId);
                    xFeeManageMaster.setContractId(task.getTaskId());
                    xFeeManageMaster.setHouseId(applyMiddle.getHouseId());
                    xFeeManageMaster.setTenantId(applyMiddle.getTenantId());
                    xFeeManageMaster.setLandId(applyMiddle.getLandId());
                    xFeeManageMaster.setEffect("yes");
                    xFeeManageMaster.setCurStatus("租住中");
                    xFeeManageMaster.setCreateTime(date);
                    xFeeManageMaster.setUpdateTime(date);
                    xFeeManageMaster.setRentType(applyMiddle.getRentType());
                    xFeeManageMaster.setPayFeeDate(applyMiddle.getPayFeeDate());
                    xFeeManageMaster.setPersonNum(applyMiddle.getPersonNum());
                    xFeeManageMaster.setLiveNum(applyMiddle.getLiveNum());
                    xFeeManageMaster.setLiveYmd(applyMiddle.getLiveYmd());
                    xFeeManageMaster.setMouthFee(applyMiddle.getMouthFee());
                    xFeeManageMaster.setManageFee(applyMiddle.getManageFee());
                    xFeeManageMaster.setDeposit(applyMiddle.getDeposit());
                    xFeeManageMaster.setWaterUnit(applyMiddle.getWaterPrice());
                    xFeeManageMaster.setPowerUnit(applyMiddle.getPowerPrice());
                    xFeeManageMaster.setGasUnit(applyMiddle.getGasPrice());
                    xFeeManageMaster.setFirstFee(NumberUtil.add(applyMiddle.getMouthFee(), applyMiddle.getManageFee(), applyMiddle.getDeposit()));
                    xFeeManageMasterService.save(xFeeManageMaster);
                    XFeeManageSon xFeeManageSon = new XFeeManageSon();
                    xFeeManageSon.setFeeId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr());
                    xFeeManageSon.setMasterId(busId);
                    xFeeManageSon.setPaymentMethod("down");
                    xFeeManageSon.setScene("签约");
                    xFeeManageSon.setUserFeeSum(NumberUtil.add(applyMiddle.getMouthFee(), applyMiddle.getManageFee(), applyMiddle.getDeposit()));
                    xFeeManageSon.setWaterNum(applyMiddle.getWaterValue());
                    xFeeManageSon.setWaterDiff(BigDecimal.ZERO);
                    xFeeManageSon.setWaterUnit(applyMiddle.getWaterPrice());
                    xFeeManageSon.setPowerNum(applyMiddle.getPowerValue());
                    xFeeManageSon.setPowerDiff(BigDecimal.ZERO);
                    xFeeManageSon.setPowerUnit(applyMiddle.getPowerPrice());
                    xFeeManageSon.setGasNum(applyMiddle.getGasValue());
                    xFeeManageSon.setGasDiff(BigDecimal.ZERO);
                    xFeeManageSon.setGasUnit(applyMiddle.getGasPrice());
                    xFeeManageSon.setWaterFee(BigDecimal.ZERO);
                    xFeeManageSon.setPowerFee(BigDecimal.ZERO);
                    xFeeManageSon.setGasFee(BigDecimal.ZERO);
                    xFeeManageSon.setMouthFee(applyMiddle.getMouthFee());
                    xFeeManageSon.setDeposit(applyMiddle.getDeposit());
                    xFeeManageSon.setManageFee(applyMiddle.getManageFee());
                    xFeeManageSon.setFreeFee(BigDecimal.ZERO);
                    xFeeManageSon.setCreateTime(date);
                    xFeeManageSon.setUpdateTime(date);
                    xFeeManageSonService.save(xFeeManageSon);
                    XContractManage xContractManage = new XContractManage();
                    xContractManage.setContractId(task.getTaskId());
                    xContractManage.setLandId(applyMiddle.getLandId());
                    xContractManage.setTenantId(applyMiddle.getTenantId());
                    xContractManage.setFileId(task.getFileId());
                    xContractManage.setHouseId(applyMiddle.getHouseId());

                    Date deadDate = null;
                    if (xFeeManageMaster.getLiveYmd().equals("日")) {
                        deadDate = DateUtil.offsetDay(xFeeManageMaster.getCreateTime(), xFeeManageMaster.getLiveNum());
                    }
                    if (xFeeManageMaster.getLiveYmd().equals("月")) {
                        deadDate = DateUtil.offsetMonth(xFeeManageMaster.getCreateTime(), xFeeManageMaster.getLiveNum());
                    }
                    if (xFeeManageMaster.getLiveYmd().equals("年")) {
                        deadDate = DateUtil.offsetMonth(xFeeManageMaster.getCreateTime(), xFeeManageMaster.getLiveNum() * 12);
                    }
                    xContractManage.setDeadDate(deadDate);
                    xContractManageService.save(xContractManage);
                } catch (Exception e) {
                    log.error("正式合同生成任务执行失败, taskId: {}", task.getTaskId(), e);
                }
            }, executorService);

            log.info("提交正式合同生成任务成功, taskId: {}, applyId: {}", task.getTaskId(), applyId);

        } catch (Exception e) {
            log.error("提交正式合同生成任务失败, applyId: {}, error: {}", applyId, e.getMessage(), e);
            throw new RuntimeException("提交正式合同生成任务失败: " + e.getMessage());
        }
    }

    /**
     * 提交异步合同生成任务
     */
    public String submitContractGenerateTask(String applyId) {
        try {
            // 获取申请信息
            LambdaQueryWrapper<XApplyMiddle> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(XApplyMiddle::getSonThreeId, applyId);
            XApplyMiddle applyMiddle = xApplyMiddleService.getOne(wrapper);

            if (applyMiddle == null) {
                throw new RuntimeException("申请信息不存在");
            }

            // 创建任务
            ContractGenerateTask task = new ContractGenerateTask(
                    applyId,
                    applyMiddle.getHouseId(),
                    applyMiddle.getLandId(),
                    applyMiddle.getTenantId()
            );
            task.setFormalSign(false);

            // 异步执行合同生成
            CompletableFuture.runAsync(() -> {
                // 获取相关信息
                ContractData contractData = getContractData(task);
                // 使用新的合同模板生成PDF
                generateContractPdf(contractData, task);
                // 将 任务ID 作为 合同ID 更新进表中
                XApplyMiddle xApplyMiddle = new XApplyMiddle();
                xApplyMiddle.setContractId(task.getTaskId());
                xApplyMiddle.setFileId(task.getFileId());
                xApplyMiddleService.update(xApplyMiddle, wrapper);
            }, executorService);

            log.info("提交合同生成任务成功, taskId: {}, applyId: {}", task.getTaskId(), applyId);
            return task.getTaskId();

        } catch (Exception e) {
            log.error("提交合同生成任务失败, applyId: {}, error: {}", applyId, e.getMessage(), e);
            throw new RuntimeException("提交合同生成任务失败: " + e.getMessage());
        }
    }

    /**
     * 获取合同数据
     */
    private ContractData getContractData(ContractGenerateTask task) {
        // 获取申请信息
        LambdaQueryWrapper<XApplyMiddle> applyWrapper = new LambdaQueryWrapper<>();
        applyWrapper.eq(XApplyMiddle::getSonThreeId, task.getApplyId());
        XApplyMiddle applyMiddle = xApplyMiddleService.getOne(applyWrapper);

        // 获取房东信息
        LambdaQueryWrapper<XPersonInfo> landlordWrapper = new LambdaQueryWrapper<>();
        landlordWrapper.eq(XPersonInfo::getPersonId, task.getLandlordId());
        landlordWrapper.eq(XPersonInfo::getPersonType, "landlord");
        XPersonInfo landlordInfo = xPersonInfoService.getOne(landlordWrapper);

        // 获取租客信息
        LambdaQueryWrapper<XPersonInfo> tenantWrapper = new LambdaQueryWrapper<>();
        tenantWrapper.eq(XPersonInfo::getPersonId, task.getTenantId());
        tenantWrapper.eq(XPersonInfo::getPersonType, "tenant");
        XPersonInfo tenantInfo = xPersonInfoService.getOne(tenantWrapper);

        // 获取房屋信息
        LambdaQueryWrapper<XHouseInfo> houseWrapper = new LambdaQueryWrapper<>();
        houseWrapper.eq(XHouseInfo::getHouseId, task.getHouseId());
        XHouseInfo houseInfo = xHouseInfoService.getOne(houseWrapper);

        return new ContractData(applyMiddle, landlordInfo, tenantInfo, houseInfo);
    }

    /**
     * 生成合同PDF
     */
    private void generateContractPdf(ContractData contractData, ContractGenerateTask task) {
        // 填充新合同模板数据
        RentalContract01 rentalContract = fillContractData(contractData, task);

        // 获取合同模板
        String template = xContractTemplateService.list().get(0).getHtmlContent();

        // 替换模板中的占位符
        String finalHtml = template
                .replace("${contractNumber}", rentalContract.getContractNumber())
                .replace("${landlordName}", rentalContract.getLandlordName())
                .replace("${landlordSex}", rentalContract.getLandlordSex())
                .replace("${landlordId}", rentalContract.getLandlordId())
                .replace("${landlordPhone}", rentalContract.getLandlordPhone())
                .replace("${tenantName}", rentalContract.getTenantName())
                .replace("${tenantSex}", rentalContract.getTenantSex())
                .replace("${tenantId}", rentalContract.getTenantId())
                .replace("${tenantPhone}", rentalContract.getTenantPhone())
                .replace("${address}", rentalContract.getAddress())
                .replace("${area}", rentalContract.getArea())
                .replace("${houseNum}", rentalContract.getHouseNum())
                .replace("${houseDesc}", rentalContract.getHouseDesc())
                .replace("${startDate}", rentalContract.getStartDate())
                .replace("${endDate}", rentalContract.getEndDate())
                .replace("${rentAmount}", rentalContract.getRentAmount())
                .replace("${qianYueShijian}", rentalContract.getQianYueShijian())
                .replace("${jiaoZuShijian}", rentalContract.getJiaoZuShijian())
                .replace("${depositAmount}", rentalContract.getDepositAmount())
                .replace("${waterPrice}", rentalContract.getWaterPrice())
                .replace("${elePrice}", rentalContract.getElePrice())
                .replace("${gasPrice}", rentalContract.getGasPrice())
                .replace("${waterNum}", rentalContract.getWaterNum())
                .replace("${eleNum}", rentalContract.getEleNum())
                .replace("${gasNum}", rentalContract.getGasNum())
                .replace("${managementFee}", rentalContract.getManagementFee())
                .replace("${extraFeeDescription}", rentalContract.getExtraFeeDescription())
                .replace("${signJia}", rentalContract.getSignJia())
                .replace("${signYi}", rentalContract.getSignYi());

        // 生成PDF
        byte[] pdfBytes;
        try {
            pdfBytes = PdfUtil.html2Pdf(finalHtml);
        } catch (IOException e) {
            throw new RuntimeException("PDF生成失败: " + e.getMessage(), e);
        }

        // 上传到云存储
        task.setFileId(winXinUtils.uploadFile("htTongFile/" + IdUtil.genShortId() + ".pdf", pdfBytes));
    }

    /**
     * 填充合同数据 - 使用新的RentalContract01模板
     */
    private RentalContract01 fillContractData(ContractData contractData, ContractGenerateTask task) {
        XApplyMiddle applyMiddle = contractData.getApplyMiddle();
        XPersonInfo landlordInfo = contractData.getLandlordInfo();
        XPersonInfo tenantInfo = contractData.getTenantInfo();
        XHouseInfo houseInfo = contractData.getHouseInfo();

        RentalContract01 contract = new RentalContract01();

        // 基本信息
        contract.setContractNumber(task.getTaskId());
        contract.setLandlordName(landlordInfo.getCardName());
        contract.setLandlordSex(landlordInfo.getSex());
        contract.setLandlordId(landlordInfo.getCardId());
        contract.setLandlordPhone(landlordInfo.getPhone());

        contract.setTenantName(tenantInfo.getCardName());
        contract.setTenantSex(tenantInfo.getSex());
        contract.setTenantId(tenantInfo.getCardId());
        contract.setTenantPhone(tenantInfo.getPhone());

        // 房屋信息
        contract.setAddress(houseInfo.getAddress());
        contract.setArea(houseInfo.getArea() != null ? houseInfo.getArea() : "0");
        contract.setHouseNum(houseInfo.getHouseName());
        contract.setHouseDesc(StrUtil.isBlank(applyMiddle.getHouseRemark()) ? "无" : applyMiddle.getHouseRemark());

        // 租赁期限 - 根据是否为正式签约使用不同的时间
        Date now = new Date();
        contract.setStartDate(DateUtil.format(now, "yyyy-MM-dd"));
        Date endDate = genTime(now, applyMiddle.getLiveNum(), applyMiddle.getLiveYmd());
        contract.setEndDate(DateUtil.format(endDate, "yyyy-MM-dd"));

        // 费用信息
        contract.setRentAmount(applyMiddle.getMouthFee().toPlainString());
        contract.setDepositAmount(applyMiddle.getDeposit().toPlainString());
        contract.setManagementFee(applyMiddle.getManageFee().toPlainString());

        // 水电费单价和表值
        contract.setWaterPrice(applyMiddle.getWaterPrice().toPlainString());
        contract.setElePrice(applyMiddle.getPowerPrice().toPlainString());
        contract.setGasPrice(applyMiddle.getGasPrice().toPlainString());


        contract.setWaterNum(applyMiddle.getWaterValue().toPlainString());
        contract.setEleNum(applyMiddle.getPowerValue().toPlainString());
        contract.setGasNum(applyMiddle.getGasValue().toPlainString());

        // 费用补充说明
        contract.setExtraFeeDescription(StrUtil.isBlank(applyMiddle.getFeeRemark()) ? "无" : applyMiddle.getFeeRemark());

        // 签约时间和交租时间 - 关键区分：正式签约使用实际时间，临时合同使用预估时间
        if (task.isFormalSign()) {
            // 正式签约：使用实际签约时间
            contract.setQianYueShijian(DateUtil.format(now, "yyyy-MM-dd"));
            log.info("正式合同签约时间: {}", contract.getQianYueShijian());
        } else {
            // 临时合同：使用预估时间
            contract.setQianYueShijian("预计签约时间：" + DateUtil.format(now, "yyyy-MM-dd"));
        }

        if ("1".equals(applyMiddle.getRentType())) {
            // 固定日期
            contract.setJiaoZuShijian("每月" + applyMiddle.getPayFeeDate() + "号");
        } else {
            // 签约周期
            contract.setJiaoZuShijian("签约日期起，每30天一次");
        }

        // 临时使用文本签名，实际应该使用图片签名
        String landUrl = winXinUtils.batchdownloadfile(JSON.parseObject(landlordInfo.getSignPic()).getString("fileID"));
        byte[] bytesJia = HttpUtil.createGet(landUrl).execute().bodyBytes();
        contract.setSignJia(PdfUtil.createImageTag(bytesJia, "100px", "50px"));
        String tenantUrl = winXinUtils.batchdownloadfile(JSON.parseObject(tenantInfo.getSignPic()).getString("fileID"));
        byte[] bytesYi = HttpUtil.createGet(tenantUrl).execute().bodyBytes();
        contract.setSignYi(PdfUtil.createImageTag(bytesYi, "100px", "50px"));

        return contract;
    }

    /**
     * 计算结束时间
     */
    private Date genTime(Date time, Integer num, String ymd) {
        Date dateTime = time;
        if ("年".equals(ymd)) {
            dateTime = DateUtil.offsetMonth(time, num * 12);
        }
        if ("月".equals(ymd)) {
            dateTime = DateUtil.offsetMonth(time, num);
        }
        if ("日".equals(ymd)) {
            dateTime = DateUtil.offsetDay(time, num);
        }
        return dateTime;
    }

    /**
     * 内部数据类
     */
    private static class ContractData {
        private final XApplyMiddle applyMiddle;
        private final XPersonInfo landlordInfo;
        private final XPersonInfo tenantInfo;
        private final XHouseInfo houseInfo;

        public ContractData(XApplyMiddle applyMiddle, XPersonInfo landlordInfo, XPersonInfo tenantInfo, XHouseInfo houseInfo) {
            this.applyMiddle = applyMiddle;
            this.landlordInfo = landlordInfo;
            this.tenantInfo = tenantInfo;
            this.houseInfo = houseInfo;
        }

        public XApplyMiddle getApplyMiddle() {
            return applyMiddle;
        }

        public XPersonInfo getLandlordInfo() {
            return landlordInfo;
        }

        public XPersonInfo getTenantInfo() {
            return tenantInfo;
        }

        public XHouseInfo getHouseInfo() {
            return houseInfo;
        }
    }
}
